「 OpenFaaS 」架构与组件概述

「 OpenFaaS 」架构与组件概述


based on 0.26.3

简介

Serverless Functions Made Simple

OpenFaaS 使开发人员可以轻松地将事件驱动(event-driven)的功能和微服务部署到 Kubernetes 中,而无需重复的模板代码。OpenFaaS 将代码或现有的二进制文件打包到 Docker 镜像中,使其具有自动缩放和服务指标的高度可扩展点。

OpenFaaS 亮点

  • 支持丰富 UI 和一键安装,便于使用
  • 借助模板库 或 Dockerfile 以任何语言编写服务和函数
  • 构建和发布代码至 Docker 镜像或其他 OCI 兼容格式的镜像中
  • 易于移植,借助 faas-netes 可在现有硬件或公有/私有云上运行
  • 支持 YAML 格式的命令行工具 — faas-cli ,用于模板化和定义函数
  • 自动缩放,支持流量高峰扩容,并在空闲时缩减直至 0
  • 版本丰富,包含社区版、标准版和商业版

设计与架构

Stack

无论是本地环境、自托管集群,还是带有托管服务(如 AWS Elastic Kubernetes Service (EKS))的平台,部署 OpenFaaS 的推荐平台都是 Kubernetes

CI / GitOps layer

OpenFaaS 既可以运行函数,也可以运行 HTTP 微服务。每个工作负载都构建到一个容器镜像中,并发布至镜像仓库。

在开发阶段,通常使用 faas-cli 手动操作完成,而在生产阶段,有几个常见的选择:

  • 源代码控制管理(SCM)系统中内置的 CI 工具

    GitHub Actions 或 GitLab pipeline 是通过在 Job 中执行 faas-cli deploy 或 faas-cli up 构建和部署函数。部署是在 Job 完成后进行的,将变更推送到集群中。如果需要访问私有 VPC 或本地的集群,可以通过使用私有且安全的入口隧道来实现

  • 使用 ArgoCD 和 Flux 等 GitOps 控制器

    GitOps 方式通常在新版本可用时立即持续部署 。部署是通过从特殊的配置库中获取预期状态来进行的

Application Layer

  • OpenFaaS gateway 提供了一个 REST API,用于管理函数、记录指标和缩放
  • NATS 用于异步函数执行和排队
  • Prometheus 提供指标并启用 Community Edition 和 OpenFaaS Pro 的自动缩放特性

使用 OpenFaaS Pro,可以通过 HTTP、Cron、AWS SQS 或 Apache Kafka 触发函数。

构成 OpenFaaS 的项目(Prometheus、Linux、OpenFaaS、NATS 和 Kubernetes)可以称为 PLONK Stack。 PLONK Stack 能够运行事件驱动(event-driven)的功能和传统的基于 HTTP 的微服务。

这些应用程序可以通过 Helm charts 或使用 ArgoCD、Flux 等 GitOps 控制器安装。

Infrastructure Layer

  • 函数的执行单元是 Pod,由 Containerd 或 Docker 管理
  • 镜像仓库将每个函数作为不可变的制品保存,可以借助镜像仓库的 REST API、UI 或 CLI 将其部署到 OpenFaaS gateway
  • Kubernetes 是允许函数跨平台,faasd 是小型安装的更简单替代方案

该 Layer 通常在探索和开发期间手动构建,在生产期间使用 Terraform 等工具构建。

工作流程

可以通过其 REST API、CLI 或 UI 访问 OpenFaas Gateway。所有服务或函数都会暴露一个默认路由,但自定义域也可以用于每个端点。

Prometheus 收集指标,这些指标可通过 OpenFaas Gateway 的 API 获得并用于自动缩放。

通过将函数的 URL 从同步的 /function/NAME 转变为异步的 /async-function/NAME,可以使用 NATS Streaming 在队列中运行调用。还可以传递一个可选的回调 URL。

faas-netes 是 OpenFaaS 最受欢迎的编排 Provider,但社区也提供了针对 Docker Swarm、Hashicorp Nomad、AWS Fargate/ECS 和 AWS Lambda 的 Provider。 Provider 使用 faas-provider SDK 构建。

Gateway

https://github.com/openfaas/faas/tree/master/gateway

API Gateway 为函数提供外部路由,并通过 Prometheus 收集云原生指标。此外,API Gateway 内置的 UI 可用于部署用户自定义的函数或来自 OpenFaaS Function Store 的函数,并调用。

API Gateway 将通过更改 Kubernetes API 中的服务副本计数来满足需求扩展功能。API Gateway 的 /system/alert endpoint 用于接收 AlertManager 生成的自定义告警。

核心特点

  • 内置 UI
  • 支持从 Function Store 部署函数或部署自定义函数
  • 通过 Prometheus 检测
  • 通过 AlertManager 和 Prometheus 自动缩放
  • 缩放至 0
  • 支持 REST API Swagger 文档

以 Kubernetes 作为编排 Provider 的流程示例

Watchdog

OpenFaaS watchdog 负责启动和监控 OpenFaaS 中的函数。通过使用 watchdog,任何二进制文件都可以成为一个函数。

watchdog 作为一个“初始化进程”,带有一个用 Golang 编写的嵌入式 HTTP 服务器,它可以支持并发请求、超时和健康检查。和 of-watchdog 类似,但非常适合流式的使用场景或需要在维护关键资源的情况,例如数据库连接、ML 模型或其他数据等请求之间。

官方提供的 templates repository 模板仓库内置了的通用编程语言的 watchdog 模板:

Name Language Version Linux base Watchdog Link
dockerfile Dockerfile N/A Alpine Linux classic Dockerfile template
go Go 1.18 Alpine Linux classic Go template
node12 NodeJS 12 Alpine Linux of-watchdog NodeJS template
node14 NodeJS 14 Alpine Linux of-watchdog NodeJS template
node16 NodeJS 16 Alpine Linux of-watchdog NodeJS template
node17 NodeJS 17 Alpine Linux of-watchdog NodeJS template
node18 NodeJS 18 Alpine Linux of-watchdog NodeJS template
node NodeJS 12 Alpine Linux classic NodeJS template
python3 Python 3 Alpine Linux classic Python 3 template
python3-debian Python 3 Debian Linux classic Python 3 Debian template
python Python 2.7 Alpine Linux classic Python 2.7 template
java11-vert-x Java and Vert.x 11 Debian GNU/Linux of-watchdog Java LTS template
java11 Java 11 Debian GNU/Linux of-watchdog Java LTS template
ruby Ruby 2.7 Alpine Linux 3.11 classic Ruby template
php7 PHP 7.4 Alpine Linux classic PHP 7 template
php8 PHP 8.1 Alpine Linux classic PHP 8 template
csharp C# N/A Debian GNU/Linux 9 classic C# template

此外,还有社区提供的 community template store 模板仓库。

Classic watchdog

Classic watchdog 最初用于所有官方 OpenFaaS 模板,但 of-watchdog 现在更受青睐。更多参考:https://github.com/openfaas/classic-watchdog/blob/master/README.md

watchdog 调用流程

of-watchdog

Reverse proxy for HTTP microservices and STDIO

of-watchdog 项目是对上述 Classic Watchdog 的补充(of-watchdog 适用于生产,是 openfaas GitHub 组织的一部分)。它于 2017 年 10 月启动,为 watchdog 和函数之间的通信提供了 STDIO 的替代方案。

of-watchdog 组件的各种模式

of-watchdog 实现了一个监听 8080 端口的 HTTP 服务器,作为运行函数和微服务的反向代理。它可以独立使用,也可以作为 OpenFaaS 容器的入口点。

这个版本的 OpenFaaS 看门狗增加了对 HTTP 代理和 STDIO 的支持,具有内存重用和高速请求服务响应的特性,主要区别在于在调用之间保持函数进程处于待命状态(warm)的能力。Classic watchdog 为每个请求 fork 一个进程,提供最高级别的可移植性,在较新的版本启用了一种 HTTP 模式,在该模式下,可以复用进程以抵消 fork 带来的延迟。

它的目的不是要取代 Classic watchdog,而是为那些需要这些功能的人提供另一种选择。

Auto Scaler

仅 OpenFaas Pro 支持。

OpenFaas Pro 的自动缩放的策略是根据以下函数标签进行配置。通过网关的所有调用,无论是同步函数 /function/ 还是异步函数 /async-function ,都采用这种自动缩放配置:

Label Description Default
com.openfaas.scale.max The maximum number of replicas to scale to. 20
com.openfaas.scale.min The minimum number of replicas to scale to. 1
com.openfaas.scale.zero Whether to scale to zero. false
com.openfaas.scale.zero-duration Idle duration before scaling to zero 15m
com.openfaas.scale.target Target load per replica for scaling 50
com.openfaas.scale.target-proportion Proportion as a float of the target i.e. 1.0 = 100% of target 0.90
com.openfaas.scale.type Scaling mode of rps, capacity, cpu rps

OpenFaaS Pro 自动缩放示例:

缩放依据

OpenFaaS Pro 提供三种自动缩放模式:

  • capacity

    基于请求或连接总量。适用于长时间运行的函数或一次只能处理有限数量请求的函数

  • rps

    基于函数每秒完成的请求。非常适合执行速度快且吞吐量高的函数

  • cpu

    基于函数的 CPU 使用率,此策略适用于受 CPU 限制的工作负载,或者在 capacity 和 RPS 模式下未提供最佳扩展配置文件的情况。这里配置的值是以 milli-CPU 为单位的,所以1000 占 1 个 CPU 核

无论哪种缩放模式,都需要在配置函数自动缩放时设置一个目标值,即函数每个副本的平均负载。OpenFaaS 会定期查询并计算当前负载,用于计算预期副本数,规则为:

desired = ready pods * ( mean load per pod / target load per pod )

此外,target-proportion 可用于调整提前或延迟缩放发生的时间:

desired = ready pods * ( mean load per pod / ( target load per pod * target-proportion ) )

流程示例

前置条件为:

  • sleep 函数应用在 capacity 模式下运行,目标负载为 5 个请求量
  • 当前 sleep 函数应用的实际负载为 15 个请求量
  • sleep 函数应用副本当前为 1
  • target-proportion 设置为 1.0,即为 100%

缩放流程为:

  1. 参考上述规则,平均每个副本的请求量为 15 / 1 = 15,超出 5 个 请求量的预期值,评估副本数为 ceil ( 1 * ( 15 / 5 * 1 ) ) = 3
  2. 副本数调整为 3 后,请求量增加到 25,此时平均每个副本的请求量为 25 / 3 = 8.33,评估副本数为 ceil ( 3 * ( 8.33 / 5 * 1 ) ) = 5
  3. 当不再有请求时,评估副本数为 ceil ( 3 * ( 0 / 5 * 1) ) = 0
  4. 是否支持缩容为 0 取决于 OpenFaaS 版本

设计初衷

在闲置时将函数缩容到零副本可以通过减少集群中所需的节点数量来节省成本,还可以减少静态大小或本地集群上的节点消耗。

在 OpenFaaS 中,缩放到零在默认情况下是关闭的,并且是 OpenFaaS Pro 一部分功能。安装后,空闲函数可以配置为在一段时间内未收到任何请求时缩减。社区建议将此数字设置为最大超时的 2 倍。

可以通过 OpenFaaS 网关的 scale_from_zero 环境变量切换从零副本向上扩展。该特性在 Kubernetes 和 faasd 上默认开启。

对不可用函数的请求,从发送处理到服务处理该请求之间的延迟成为冷启动。

  • 如果不想冷启动怎么办?

    OpenFaaS 中的冷启动是严格可选的。对于时间敏感的操作,可以通过至少有 1 个或多个副本来避免冷启动。通过关键函数禁止缩放到 0,或者通过异步路由调用来实现,从而将请求时间与调用者分离

  • 冷启动到底发生了什么?

    冷启动包括以下流程:创建请求在节点上调度容器、找到合适的节点、拉取 Docker 镜像、在容器启动并运行后进行初始检查。可以通过在每个节点上预热镜像以及将 Kubernetes Liveness 和 Readiness Probes 设置为更快的节奏运行,可以降低总开销。更多参考:冷启动进行优化的说明

    当启用 scale_from_zero 时,缓存会保留在内存中,根据每个函数的就绪情况,如果收到请求时函数未就绪,则 HTTP 连接将被阻止,函数将缩放到最小副本,一旦副本可用,请求就会按正常方式处理。具体流程在网关组件的日志中可以看到。更多参考:冷启动概述

  • 如果函数在按比例缩小时仍在运行怎么办?

    不应该发生,前提是已经为函数的空闲检测设置了足够的值。但如果是这样,OpenFaaS watchdog 和官方函数模板将允许函数正常终止。更多参考:为 OpenFaaS 用户改进长时间运行的作业

Prometheus 将监控指标发给 AlertManager 之后,AlertManager 会调用 /system/alert 接口,这个接口的 handler 是由 handlers.MakeAlertHandler 方法生成。MakeAlertHandler 方法接收的参数是 ServiceQuery。ServiceQuery 是一个接口,它有两个函数,用来获取或者设置最大的副本数。

1
2
3
4
5
// ServiceQuery provides interface for replica querying/setting
type ServiceQuery interface {
GetReplicas(service, namespace string) (response ServiceQueryResponse, err error)
SetReplicas(service, namespace string, count uint64) error
}

MakeAlertHandler 的函数主要是从 http.Request 中读取 body,然后反序列化成 PrometheusAlert 对象,该对象是一个数组类型,支持对多个函数进行缩放。反序列化之后,调用 handleAlerts 方法,而 handleAlerts 对 alerts 进行遍历,针对每个 alert 调用了 scaleService 方法。scaleService 才是真正处理伸缩服务的函数。

对于 OpenFaaS CE 而言,Auto Scaler 能力相对而言较低,仅支持最大和最小的副本数:

Label Description Default
com.openfaas.scale.max The maximum number of replicas to scale to. 5
com.openfaas.scale.min The minimum number of replicas to scale to. 1
com.openfaas.scale.factor Define the overall scaling behavior of the function. 20%

Faas Provider

faas-provider 提供函数的 CRUD API 以及调用功能。

faas-provider 是一个用 Go 编写的 SDK,它符合 OpenFaaS Provider 的 HTTP REST API。实现接口声明的 provider 应该与 OpenFaaS 工具链和生态系统兼容,包括 UI、CLI、Function Store 和 Template Store。

每个 Provider 都实现以下行为:

  • 函数(或微服务)的 CRUD
  • 通过代理调用函数
  • 函数缩放
  • Secret 的 CRUD(可选)
  • 日志流(可选)
Provider Overview
Kubernetes Provider (faas-netes) 针对 Kubernetes 的官方 OpenFaaS Provider,默认内置在 Helm chart 中
faasd Provider (faasd) OpenFaaS 的另一种思路实现,抛去了 Kubernetes 的成本和复杂性。可以在要求非常低的单个主机上运行,且具备快速、易于管理的特点。其底层是由 Containerd 、容器网络接口 (CNI) 以及来自 OpenFaaS 项目的核心组件构成
Docker Swarm Provider faas-swarm) 针对 Docker Swarm 的官方 OpenFaaS Provider,现已弃用且不再维护
faas-memory Provider (faas-memory) 使用本地代码内存空间存储状态,仅用于测试目的和简单示例
社区 Provider 参考实现:https://github.com/openfaas/faas/blob/master/community.md#openfaas-providers

faas-netes

faasd

Log Provider

OpenFaaS 支持集成自定义的 Log Provider。

Log Provider 是一个 HTTP 服务器,对外暴露 /system/logs endpoint,该 endpoint 支持具有以下查询参数的 GET 请求:

  • name - 函数名称(必需)
  • instance - 容器名称(可选),允许从特定函数实例中请求日志
  • since - 日志起始时间(可选)
  • tail - 日志消息返回的最大数量,<=0 表示无限制
  • follow - 允许用户请求日志流直至超时(启用时,服务器必须使用 HTTP 分块编码来发送日志的实时流)

默认情况下,OpenFaaS Gateway 会将日志请求代理到函数 Provider。可以在 OpenFaaS Gateway 服务中设置 logs_provider_url 环境变量,OpenFaaS Gateway 会将日志请求代理到此 URL,实现 Log Provider 替换。

Log Provider Overview
Kubernetes Provider (faas-netes) Kubernetes Provider 并从 Kubernetes API 查询日志
faasd Provider (faasd) 从 journal 服务中查询日志,按函数和核心服务存储
Grafana Provider (openfaas-loki) 社区提供的 Log Provider,使用 Grafana Loki 来收集和查询功能日志
自定义 Provider 借助 github.com/openfaas/faas-provider/logs 包提供的封装,可以构建自定义的 Log Provider HTTP 服务,参考示例:https://github.com/openfaas/faas-provider/tree/master/logs/example
Author

Shen Xianghong

Posted on

2023-05-08

Updated on

2023-06-19

Licensed under